// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_RENDER_TEXT_MAC_H_
#define UI_GFX_RENDER_TEXT_MAC_H_

#include <ApplicationServices/ApplicationServices.h>
#include <stddef.h>
#include <stdint.h>

#include <string>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/render_text.h"

namespace gfx {

// RenderTextMac is the Mac implementation of RenderText that uses CoreText for
// layout and Skia for drawing.
//
// Note: The current implementation only supports drawing and sizing the text,
//       but not text selection or cursor movement.
class GFX_EXPORT RenderTextMac : public RenderText {
public:
    RenderTextMac();
    ~RenderTextMac() override;

    // RenderText:
    scoped_ptr<RenderText> CreateInstanceOfSameType() const override;
    bool MultilineSupported() const override;
    const base::string16& GetDisplayText() override;
    Size GetStringSize() override;
    SizeF GetStringSizeF() override;
    SelectionModel FindCursorPosition(const Point& point) override;
    std::vector<FontSpan> GetFontSpansForTesting() override;

protected:
    // RenderText:
    int GetDisplayTextBaseline() override;
    SelectionModel AdjacentCharSelectionModel(
        const SelectionModel& selection,
        VisualCursorDirection direction) override;
    SelectionModel AdjacentWordSelectionModel(
        const SelectionModel& selection,
        VisualCursorDirection direction) override;
    Range GetGlyphBounds(size_t index) override;
    std::vector<Rect> GetSubstringBounds(const Range& range) override;
    size_t TextIndexToDisplayIndex(size_t index) override;
    size_t DisplayIndexToTextIndex(size_t index) override;
    bool IsValidCursorIndex(size_t index) override;
    void OnLayoutTextAttributeChanged(bool text_changed) override;
    void OnDisplayTextAttributeChanged() override;
    void OnTextColorChanged() override;
    void EnsureLayout() override;
    void DrawVisualText(internal::SkiaTextRenderer* renderer) override;

private:
    FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Mac_ElidedText);

    struct TextRun {
        CTRunRef ct_run;
        SkPoint origin;
        std::vector<uint16_t> glyphs;
        std::vector<SkPoint> glyph_positions;
        SkScalar width;
        Font font;
        SkColor foreground;
        bool underline;
        bool strike;
        bool diagonal_strike;

        TextRun();
        ~TextRun();
    };

    // Returns the width used to draw |layout_text_|.
    float GetLayoutTextWidth();

    // Computes the size used to draw |line|. Stores the baseline position into
    // |baseline|.
    gfx::SizeF GetCTLineSize(CTLineRef line, SkScalar* baseline);

    // Creates Core Text line object and its attributes for the given text and
    // returns the line. |attributes| keeps the ownership of the text attributes.
    // See the comments of ArrayStyles() implementation for the ownership details.
    base::ScopedCFTypeRef<CTLineRef> EnsureLayoutInternal(
        const base::string16& text,
        base::ScopedCFTypeRef<CFMutableArrayRef>* attributes);

    // Applies RenderText styles to |attr_string| with the given |ct_font|.
    // Returns the array of attributes to keep the ownership of the attributes.
    // See the comments in .cc file for the details.
    base::ScopedCFTypeRef<CFMutableArrayRef> ApplyStyles(
        const base::string16& text,
        CFMutableAttributedStringRef attr_string,
        CTFontRef ct_font);

    // Updates |runs_| based on |line_| and sets |runs_valid_| to true.
    void ComputeRuns();

    // Clears cached style. Doesn't update display text (e.g. eliding).
    void InvalidateStyle();

    // The Core Text line of text. Created by |EnsureLayout()|.
    base::ScopedCFTypeRef<CTLineRef> line_;

    // Array to hold CFAttributedString attributes that allows Core Text to hold
    // weak references to them without leaking.
    base::ScopedCFTypeRef<CFMutableArrayRef> attributes_;

    // Visual dimensions of the text. Computed by |EnsureLayout()|.
    SizeF string_size_;

    // Common baseline for this line of text. Computed by |EnsureLayout()|.
    SkScalar common_baseline_;

    // Visual text runs. Only valid if |runs_valid_| is true. Computed by
    // |ComputeRuns()|.
    std::vector<TextRun> runs_;

    // Indicates that |runs_| are valid, set by |ComputeRuns()|.
    bool runs_valid_;

    DISALLOW_COPY_AND_ASSIGN(RenderTextMac);
};

} // namespace gfx

#endif // UI_GFX_RENDER_TEXT_MAC_H_
